package tree.concurrent.triangulation.kruskals;/*
    Coordinator.java

    Serves to slow down execution of a collection of threads, so that
    behavior is visible on the screen, and to notify all running threads
    when the user wants them to die.

    Michael L. Scott, November 2012, based on code
    originally written in 2002.
 */

// import java.util.*;
// import java.lang.*;

// The Coordinator serves to slow down execution, so that behavior is
// visible on the screen, and to notify all running threads when the user
// wants them to die.
//
class Coordinator {
    private boolean open = true;
        // set to false temporarily when threads are supposed to die.
    private boolean running = true;
        // set to false when threads are supposed to pause.
    private int numThreads = 0;
        // number of active worker threads.  Maintained by register and
        // unregister methods.

    // A thread terminates early by throwing itself a KilledException.
    //
    public class KilledException extends Throwable {}

    public synchronized void register() {
        numThreads++;
    }

    public synchronized void unregister() {
        numThreads--;
        notifyAll();
            // so event thread knows to inspect numThreads again
    }

    // Pause or die if so instructed.
    //
    private synchronized void gate()
            throws KilledException {
        if (!open) {
            numThreads--;
            notify();
            throw new KilledException();
        }
        while (!running) {
            try {
                wait();
            } catch(InterruptedException e) {};
            if (!open) {
                numThreads--;
                notify();
                throw new KilledException();
            }
        }
    }

    // Wait a bit before proceeding through gate.
    //
    public void hesitate() throws KilledException {
        try {
            Thread.sleep(50);   // milliseconds
        } catch(InterruptedException e) {};
        gate();
    }

    // Toggle running.  Resume paused threads if appropriate.
    //
    public synchronized void toggle() {
        running = !running;
        if (running) {
            notifyAll();
        }
    }

    // Kill all threads using the coordinator.
    //
    public synchronized void stop() {
        open = false;
        notifyAll();
        while (numThreads > 0) {
            try {
                wait();
            } catch(InterruptedException e) {};
        }
        open = true;
        running = true;
    }

    // (Default constructor only)
}
